/* FILE : ui.c */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gdk-pixbuf/gdk-pixdata.h>
#include <standard_im.h>

#include "im.h"
#include "ui.h"
#include "imm.h"

#define PREEDIT_FONT	"STsuperfont 12"
#define PREEDIT_FG	"#000000"
#define PREEDIT_BG	"#FFFFFF"
#define CANDIDATE_FONT	"STsuperfont 12"
#define CANDIDATE_FG	"#000000"
#define CANDIDATE_BG	"#FFFFFF"
#define NUMBER_FONT	"Sans Bold 9"
#define NUMBER_FG	"#600000"
#define	NUMBER_BG	"#000000"
#define STATUS_FONT	"Sans 9"
#define STATUS_FG	"#000000"
#define STATUS_BG	"#FFFFFF"

#define OPACITY_PROP    "_NET_WM_WINDOW_OPACITY"
#define CANDIDATE_ALPHA 0xc0000000 /* 0.75 of 0xffffffff */

static WindowData *preedit, *lu_vert, *lu_horz;
static GtkWidget *phrase_hint;
static GtkWidget *up_arrow, *down_arrow, *left_arrow, *right_arrow;
static GtkWidget *lu_horz_status_label, *lu_vert_status_label;

static PangoAttrList *cand_num_attr = NULL;
static PangoAttrList *hi_cand_num_attr = NULL;
static PangoAttrList *phr_num_attr = NULL;
static PangoAttrList *hi_phr_num_attr = NULL;

static LookupData *lookup_data = NULL;

void
ui_init_preedit_window()
{
#if DEBUG
	fprintf(stderr, "xaux : init preedit window\n");
#endif

	gtk_rc_parse_string("style 'unihan-compose-window-style' "
			    "{"
			    "bg_pixmap[NORMAL] = '<none>'"
			    "}"
			    "widget 'unihan-compose-window' style 'unihan-compose-window-style'");

	preedit = g_new0(WindowData, 1);
	preedit->window = gtk_window_new(GTK_WINDOW_POPUP);
	gtk_widget_set_name(preedit->window, "unihan-compose-window");
	gtk_window_set_wmclass(GTK_WINDOW(preedit->window), 
						"unihan", "LookupAux");
	gtk_container_set_border_width(GTK_CONTAINER(preedit->window), 1);
	g_signal_connect_after(G_OBJECT(preedit->window), "realize",
			       G_CALLBACK(ui_preedit_realized), NULL);

	//gtk_window_set_has_frame(GTK_WINDOW(preedit->window), TRUE);
	//gtk_window_set_frame_dimensions(GTK_WINDOW(preedit->window), 1, 1, 1, 1);
        gtk_window_set_keep_above(GTK_WINDOW(preedit->window), TRUE);
        gtk_window_set_decorated(GTK_WINDOW(preedit->window), FALSE);
        gtk_window_set_type_hint(GTK_WINDOW(preedit->window), GDK_WINDOW_TYPE_HINT_MENU);
        gtk_window_set_accept_focus(GTK_WINDOW(preedit->window), FALSE);

	preedit->child = gtk_label_new(NULL);
	gtk_misc_set_alignment(GTK_MISC(preedit->child), 0.0, 0.5);

	gtk_widget_show_all(preedit->child);
	gtk_container_add(GTK_CONTAINER(preedit->window), preedit->child);

	preedit->poppedup = FALSE;

	gdk_color_parse(PREEDIT_FG, &preedit->fg);
	gdk_color_parse(PREEDIT_BG, &preedit->bg);
	gtk_widget_modify_fg(preedit->window, GTK_STATE_NORMAL, &preedit->fg);
	gtk_widget_modify_fg(preedit->child, GTK_STATE_NORMAL, &preedit->fg);
	gtk_widget_modify_bg(preedit->window, GTK_STATE_NORMAL, &preedit->bg);
	gtk_widget_modify_bg(preedit->child, GTK_STATE_NORMAL, &preedit->bg);
	gtk_widget_modify_base(preedit->window, GTK_STATE_NORMAL, &preedit->bg);
	gtk_widget_modify_base(preedit->child, GTK_STATE_NORMAL, &preedit->bg);
}

void
ui_draw_preedit(int x, int y, char *string)
{
	GtkRequisition req;
	int screen_w, screen_h;
	int newx = x, newy = y;

	gtk_label_set_text(GTK_LABEL(preedit->child), string);

	gtk_window_resize(GTK_WINDOW(preedit->window), 1, 1);
	gtk_widget_size_request(preedit->window, &req);

	// don't draw it where the user can't see it ...
	screen_w = gdk_screen_width();
	screen_h = gdk_screen_height();
	if (newx + req.width >= screen_w) {
		newx = screen_w - req.width;
		// but don't overdo it
		if (newx < 0) newx = 0;
	}
	if (newy + req.height >= screen_h) {
		newy -= (24 + req.height);
	} else {
		newy += 5;
	}

	preedit->x = newx;
	preedit->y = newy;

	gtk_window_move(GTK_WINDOW(preedit->window), newx, newy);

	if (!preedit->poppedup) {
		preedit->poppedup = TRUE;
		gtk_widget_show(preedit->window);
	}

	if (lu_vert->poppedup) {
		ui_reposition_lu_vert(x, y);
	} else if (lu_horz->poppedup) {
		ui_reposition_lu_horz(x, y);
	}
}

void
ui_hide_preedit(void)
{
	if (!GTK_WIDGET_MAPPED(preedit->window))
		return;
	gtk_widget_hide(preedit->window);
	preedit->poppedup = FALSE;
}

void
ui_preedit_realized(GtkWidget *w, gpointer data)
{
	GdkColormap *colormap = gtk_widget_get_colormap(w);
	gdk_colormap_alloc_color(colormap, &preedit->fg, TRUE, TRUE);
	//gdk_window_set_background(GTK_WINDOW(preedit->window)->frame, &preedit->fg);
	//gdk_window_set_back_pixmap(preedit->window->window, NULL, FALSE);
}

void
ui_init_lookup_data()
{
#if DEBUG
	fprintf(stderr, "xaux : init lookup data\n");
#endif
}

void
ui_init_lu_horz_window()
{
	GtkWidget *bigbox, *box, *bar;
	GdkColor color;

	gtk_rc_parse_string("style 'unihan-candidate-h-window-style' "
			    "{"
			    "bg_pixmap[NORMAL] = '<none>'"
			    "}"
			    "widget 'unihan-candidate-h-window' style 'unihan-candidate-h-window-style'");

	lu_horz = g_new0(WindowData, 1);
	lu_horz->window = gtk_window_new(GTK_WINDOW_POPUP);
	gtk_widget_set_name(lu_horz->window, "unihan-candidate-h-window");
	gtk_container_set_border_width(GTK_CONTAINER(lu_horz->window), 0);
	gtk_window_set_has_frame(GTK_WINDOW(lu_horz->window), TRUE);
	gtk_window_set_frame_dimensions(GTK_WINDOW(lu_horz->window), 1, 1, 1, 1);

	bigbox = gtk_vbox_new(FALSE, 4);
	gtk_container_set_border_width(GTK_CONTAINER(bigbox), 4);

	box = gtk_hbox_new(FALSE, 8);
	gtk_container_set_border_width(GTK_CONTAINER(box), 0);
	lu_horz->child = box;

	bar = gtk_hbox_new(FALSE, 4);
	lu_horz_status_label = gtk_label_new(NULL);

	left_arrow = gtk_image_new();
	right_arrow = gtk_image_new();
	g_signal_connect_after(G_OBJECT(lu_horz->window), "realize",
			       G_CALLBACK(ui_lu_horz_realized), NULL);
	gtk_misc_set_alignment(GTK_MISC(left_arrow), 0.5, 0.5);
	gtk_misc_set_alignment(GTK_MISC(right_arrow), 0.5, 0.5);
	gtk_misc_set_alignment(GTK_MISC(lu_horz_status_label), 0.0, 0.5);
	gtk_box_pack_start(GTK_BOX(bar), lu_horz_status_label, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(bar), left_arrow, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(bar), right_arrow, FALSE, FALSE, 0);
	
	gtk_box_pack_start_defaults(GTK_BOX(bigbox), box);
	gtk_box_pack_start_defaults(GTK_BOX(bigbox), bar);
	gtk_widget_show_all(bigbox);

	gtk_container_add(GTK_CONTAINER(lu_horz->window), bigbox);

	lu_horz->poppedup = FALSE;

	gtk_widget_modify_bg(lu_horz->window, GTK_STATE_NORMAL, &lu_horz->bg);
	gtk_widget_modify_base(lu_horz->window, GTK_STATE_NORMAL, &lu_horz->bg);
	gtk_widget_modify_fg(lu_horz_status_label, GTK_STATE_NORMAL, &color);
}

void
ui_init_lu_vert_window()
{
	GtkWidget *box;
	GtkWidget *bar;
	//GdkPixmap *arrow;
	//GdkBitmap *arrow_mask = NULL;
	//GdkColormap *colormap;
	PangoFontDescription *fontdesc;

	gtk_rc_parse_string("style 'unihan-candidate-v-window-style' "
			    "{"
			    "bg_pixmap[NORMAL] = '<none>'"
			    "}"
			    "widget 'unihan-candidate-v-window' style 'unihan-candidate-v-window-style'");

	lu_vert = g_new0(WindowData, 1);
	lu_vert->window = gtk_window_new(GTK_WINDOW_POPUP);
	gtk_widget_set_name(lu_vert->window, "unihan-candidate-v-window");
	gtk_container_set_border_width(GTK_CONTAINER(lu_vert->window), 0);
        //gtk_window_set_has_frame(GTK_WINDOW(lu_vert->window), TRUE);
	//gtk_window_set_frame_dimensions(GTK_WINDOW(lu_vert->window), 1, 1, 1, 1);
        gtk_window_set_keep_above(GTK_WINDOW(lu_vert->window), TRUE);
        gtk_window_set_decorated(GTK_WINDOW(lu_vert->window), FALSE);
        gtk_window_set_type_hint(GTK_WINDOW(lu_vert->window), GDK_WINDOW_TYPE_HINT_MENU);
        //gtk_window_set_skip_taskbar_hint(GTK_WINDOW(lu_vert->window), TRUE);
        //gtk_window_set_skip_pager_hint(GTK_WINDOW(lu_vert->window), TRUE);
        gtk_window_set_accept_focus(GTK_WINDOW(lu_vert->window), FALSE);

	box = gtk_vbox_new(FALSE, 4);
	gtk_container_set_border_width(GTK_CONTAINER(box), 4);
	lu_vert->child = box;
	
	bar = gtk_hbox_new(FALSE, 0);
	phrase_hint = gtk_label_new(NULL);
	fontdesc = pango_font_description_from_string(PREEDIT_FONT);
	gtk_widget_modify_font(phrase_hint, fontdesc);

	up_arrow = gtk_image_new();
	down_arrow = gtk_image_new();
	g_signal_connect_after(G_OBJECT(lu_vert->window), "realize",
			       G_CALLBACK(ui_lu_vert_realized), NULL);

	lu_vert_status_label = gtk_label_new(NULL);
	
	gtk_misc_set_alignment(GTK_MISC(up_arrow), 0.5, 1.0);
	gtk_misc_set_alignment(GTK_MISC(down_arrow), 0.5, 1.0);
	gtk_misc_set_alignment(GTK_MISC(lu_vert_status_label), 0.0, 1.0);

	gtk_box_pack_start(GTK_BOX(bar), lu_vert_status_label, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(bar), up_arrow, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(bar), down_arrow, FALSE, FALSE, 0);
	gtk_box_pack_end_defaults(GTK_BOX(box), bar);

	gtk_widget_show_all(box);
	gtk_container_add(GTK_CONTAINER(lu_vert->window), box);

	lu_vert->poppedup = FALSE;
}

void
ui_draw_lu_horz(int x, int y, const LookupData *data)
{
	//GList *hbox_child, *hbox_children;
	GtkWidget *hbox = lu_horz->child;
	int i;
	int total_pages, curr_page;
	gchar *status;

	// then add them to the box 
	for (i = 0; i < data->num_cands; i++) {
		if ( i == data->selected_item ) {
			gtk_label_set_attributes(GTK_LABEL(data->cand[i]), 
						 hi_cand_num_attr);
		} else {
			gtk_label_set_attributes(GTK_LABEL(data->cand[i]), 
						 cand_num_attr);
		}
		gtk_box_pack_start_defaults(GTK_BOX(hbox),
				            data->cand[i]);
	}

	total_pages = (data->total_cands-1) / 9 + 1;
	curr_page = data->lu_curr_cand / 9 + 1;
	status = g_strdup_printf("%d/%d", curr_page, total_pages);
	gtk_label_set_text(GTK_LABEL(lu_horz_status_label), status);
	g_free(status);

	if (data->have_next)
		gtk_widget_show(right_arrow);
	else
		gtk_widget_hide(right_arrow);

	if (data->have_prev)
		gtk_widget_show(left_arrow);
	else
		gtk_widget_hide(left_arrow);

	if (total_pages > 1)
		gtk_widget_show(lu_horz_status_label);
	else
		gtk_widget_hide(lu_horz_status_label);

	if (!lu_horz->poppedup) {
		lu_horz->poppedup = TRUE;
		gtk_widget_show(lu_horz->window);
	}

	ui_reposition_lu_horz(x, y);
}

void
ui_draw_lu_vert(int x, int y, const LookupData *data)
{
	//GList *vbox_child, *vbox_children;
	GtkWidget *vbox = lu_vert->child;
	int i;
	int curr_page, total_pages;
	char *statstr;

	// then add them to the box 
	for (i = 0; i < data->num_cands; i++) {
		if ( i == data->selected_item ) {
			/*gtk_label_set_attributes(GTK_LABEL(data->cand[i]), 
						 (data->is_phrase) ?
						    hi_phr_num_attr : hi_cand_num_attr);*/
		} else {
			/*gtk_label_set_attributes(GTK_LABEL(data->cand[i]), 
						 (data->is_phrase) ?
						    phr_num_attr : cand_num_attr);*/
		}
#if DONT_UNPARENT
                if (gtk_widget_get_parent(data->cand[i]) == NULL) {
#endif
		gtk_box_pack_start_defaults(GTK_BOX(vbox),
				            data->cand[i]);
#if DONT_UNPARENT
                }
                gtk_widget_show(data->cand[i]);
#endif
	}
#if DONT_UNPARENT
        for (i=data->num_cands; i>0 && i<9; i++) {
                gtk_widget_hide(data->cand[i]);
        }
#endif

	total_pages = (data->total_cands-1) / 9 + 1;
	curr_page = data->lu_curr_cand / 9 + 1;
	statstr = g_strdup_printf("%d/%d", curr_page, total_pages);
	gtk_label_set_text(GTK_LABEL(lu_vert_status_label), statstr);
	g_free(statstr);

	/*if (data->have_next)
		gtk_widget_show(down_arrow);
	else
		gtk_widget_hide(down_arrow);

	if (data->have_prev)
		gtk_widget_show(up_arrow);
	else
		gtk_widget_hide(up_arrow);*/

	if (total_pages > 1)
		gtk_widget_show(lu_vert_status_label);
	else
		gtk_widget_hide(lu_vert_status_label);

	if (!lu_vert->poppedup) {
                lu_vert->x = x;
	}
	ui_reposition_lu_vert(lu_vert->x, y);

        if (!lu_vert->poppedup) {
		lu_vert->poppedup = TRUE;
		gtk_widget_show(lu_vert->window);
        }
}

void
ui_reposition_lu_horz(int x, int y)
{
	GtkRequisition pe_req, req;
	int screen_w = 0, screen_h = 0;
	int newx = x, newy = y;
	int width_over = 0;//, height_over = 0;

	if (preedit->poppedup) {
		newx = preedit->x;
		gtk_widget_size_request(preedit->window, &pe_req);
		newy = preedit->y + pe_req.height + 1;
	}

	// force resize of window 
	gtk_window_resize(GTK_WINDOW(lu_horz->window), 50, 1);
	//see how much space we request
	gtk_widget_size_request(lu_horz->window, &req);
	
	screen_w = gdk_screen_width();
	screen_h = gdk_screen_height();

	width_over = (newx + req.width) - screen_w;
	if (width_over > 0)
		newx -= width_over;

	// FIXME: consider height_over case

	lu_horz->x = newx;
	lu_horz->y = newy;
	gtk_window_move(GTK_WINDOW(lu_horz->window), newx, newy);
}

void
ui_reposition_lu_vert(int x, int y)
{
	GtkRequisition pe_req, req;
	int screen_w = 0, screen_h = 0;
	int newx = x, newy = y;
	//int width_over = 0;
	//int height_over = 0;

	if (preedit->poppedup) {
		newy = preedit->y;
		gtk_widget_size_request(preedit->window, &pe_req);
		newx = preedit->x + pe_req.width + 1;
	}

	// force resize of window
	gtk_window_resize(GTK_WINDOW(lu_vert->window), 50, 1);
	// see how much space we request
	gtk_widget_size_request(lu_vert->window, &req);
	
	screen_w = gdk_screen_width();
	screen_h = gdk_screen_height();

#if USE_PREEDIT_AUX   // Since we don't draw preedit window anymore, we need a new algorithm
        
	int height_over = (newy + req.height) - screen_h;
	if (height_over > 0)
		newy -= height_over;

	int width_over = (newx + req.width) - screen_w;
	if (width_over > 0) {
		if ((pe_req.width + req.width) > screen_w)  // trouble
			width_over = preedit->x;

		newx -= width_over;
		if (preedit->poppedup) {
			preedit->x -= width_over;
			gtk_window_move(GTK_WINDOW(preedit->window), preedit->x, preedit->y);
		}
	}
#else
        if (newy + req.height + 24 >= screen_h) {
                newy -= (24 + req.height);
        } else {
                newy += 24;
        }
        if (newx + req.width >= screen_w) {
                newx = screen_w - req.width;
                if (newx < 0) newx = 0;
        }
#endif

        lu_vert->x = newx;
	lu_vert->y = newy;
	gtk_window_move(GTK_WINDOW(lu_vert->window), newx, newy);
}

void
ui_lu_horz_realized(GtkWidget *w, gpointer data)
{
	GdkColormap *colormap;
	GdkColor fg, bg;

	colormap = gtk_widget_get_colormap(w);
	gdk_colormap_alloc_color(colormap, &fg, TRUE, TRUE);
	gdk_colormap_alloc_color(colormap, &bg, TRUE, TRUE);
	gdk_colormap_alloc_color(colormap, &lu_horz->fg, TRUE, TRUE);
	
	gdk_window_set_background(GTK_WINDOW(lu_horz->window)->frame, &lu_horz->fg);
	gdk_window_set_back_pixmap(lu_horz->window->window, NULL, FALSE);
}

void
ui_lu_vert_realized(GtkWidget *w, gpointer data)
{
	//GdkBitmap *arrow_mask;
	GdkColormap *colormap;
	GdkColor fg, bg;

	colormap = gtk_widget_get_colormap(w);
	gdk_colormap_alloc_color(colormap, &fg, TRUE, TRUE);
	gdk_colormap_alloc_color(colormap, &bg, TRUE, TRUE);
	gdk_colormap_alloc_color(colormap, &lu_vert->fg, TRUE, TRUE);
	
	gdk_window_set_background(GTK_WINDOW(lu_vert->window)->frame, &lu_vert->fg);
	gdk_window_set_back_pixmap(lu_vert->window->window, NULL, FALSE);

        //gdouble alpha = gconf_client_get_float(client, CANDIDATE_ALPHA_KEY, NULL);
        //set_opacity_prop(lu_vert->window->window, alpha * 0xffffffff);
}

void
ui_hide_lookup(void)
{
	if (GTK_WIDGET_MAPPED(lu_horz->window)) {
		gtk_widget_hide(lu_horz->window);
		lu_horz->poppedup = FALSE;
	}
	if (GTK_WIDGET_MAPPED(lu_vert->window)) {
		gtk_widget_hide(lu_vert->window);
		lu_vert->poppedup = FALSE;
	}
}

LookupData *
ui_parse_lookup_values(IM1Event *imev)
{
	LookupData *d = NULL;
	char numstr[] = "1 ";
	char *candstr;

	d = (LookupData *)malloc(sizeof(LookupData));
	bzero(d, sizeof(LookupData));

	d->have_prev = 0;
	d->have_next = 0;
	d->is_phrase = 0;

	d->total_cands = 2;
	d->lu_curr_cand = 0;
	d->selected_item = 1;

	d->num_cands = 2;

	candstr = g_strconcat(numstr, imev->string0, NULL);
	gtk_label_set_text(GTK_LABEL(d->cand[0]), candstr);
	g_free(candstr);

	numstr[0] = '2';
	candstr = g_strconcat(numstr, imev->string1, NULL);
	gtk_label_set_text(GTK_LABEL(d->cand[1]), candstr);
	g_free(candstr);

	return lookup_data;
}

void
ui_unparent_candidates(void) 
{
	int i;
	for (i = 0; i < 9; i++) {
		GtkWidget *w, *p;
		w = lookup_data->cand[i];
		p = gtk_widget_get_parent(w);
		if (p != NULL) {
			gtk_container_remove(GTK_CONTAINER(p), w);
		}
	}
}

void
ui_init_attributes()
{
	return;
}

void
ui_real_init_attributes(PangoFontDescription *fontdesc,
		GdkColor *fg,
		GdkColor *bg)
{
	PangoAttribute *attr = NULL;

	if (cand_num_attr)
		pango_attr_list_unref(cand_num_attr);
	if (phr_num_attr)
		pango_attr_list_unref(phr_num_attr);
	if (hi_cand_num_attr)
		pango_attr_list_unref(hi_cand_num_attr);
	if (hi_phr_num_attr)
		pango_attr_list_unref(hi_phr_num_attr);
		
	cand_num_attr = pango_attr_list_new();
	phr_num_attr = pango_attr_list_new();
	hi_cand_num_attr = pango_attr_list_new();
	hi_phr_num_attr = pango_attr_list_new();
	pango_attr_list_ref(cand_num_attr);
	pango_attr_list_ref(phr_num_attr);
	pango_attr_list_ref(hi_cand_num_attr);
	pango_attr_list_ref(hi_phr_num_attr);

	attr = pango_attr_font_desc_new(fontdesc);
	attr->start_index = 0; attr->end_index = 2;
	pango_attr_list_insert(cand_num_attr, attr);
	pango_attr_list_insert(phr_num_attr, attr);
	pango_attr_list_insert(hi_cand_num_attr, attr);
	pango_attr_list_insert(hi_phr_num_attr, attr);
	
	attr = pango_attr_foreground_new(fg->red, fg->green, fg->blue);
	attr->start_index = 0; attr->end_index = 2;
	pango_attr_list_insert(cand_num_attr, attr);

	attr = pango_attr_foreground_new(0, 0, 0x6000);
	attr->start_index = 0; attr->end_index = 2;
	pango_attr_list_insert(phr_num_attr, attr);

	// highlighted candidate color
	attr = pango_attr_foreground_new(bg->red, bg->green, bg->blue);
	attr->start_index = 0; attr->end_index = G_MAXUINT;
	pango_attr_list_insert(hi_cand_num_attr, attr);
	attr = pango_attr_background_new(fg->red, fg->green, fg->blue);
	attr->start_index = 0; attr->end_index = G_MAXUINT;
	pango_attr_list_insert(hi_cand_num_attr, attr);

	// highlighted phrase candidate color
	attr = pango_attr_foreground_new(bg->red, bg->green, bg->blue);
	attr->start_index = 0; attr->end_index = G_MAXUINT;
	pango_attr_list_insert(hi_phr_num_attr, attr);
	attr = pango_attr_background_new(fg->red, fg->green, fg->blue);
	attr->start_index = 0; attr->end_index = G_MAXUINT;
	pango_attr_list_insert(hi_phr_num_attr, attr);
}


